package com.wandong.cinema.service.impl;

import com.wandong.cinema.entity.Show;
import com.wandong.cinema.entity.Ticket;
import com.wandong.cinema.service.ShowService;
import com.wandong.cinema.service.TicketService;
import com.wandong.cinema.util.IdGenerator;
import com.wandong.cinema.util.InputUtil;
import com.wandong.cinema.util.LogUtil;
import com.wandong.cinema.entity.Hall;
import com.wandong.cinema.entity.Movie;
import com.wandong.cinema.service.HallService;
import com.wandong.cinema.service.MovieService;
import com.wandong.cinema.service.impl.HallServiceImpl;
import com.wandong.cinema.service.impl.MovieServiceImpl;


import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class TicketServiceImpl implements TicketService {
    // 存储所有票，票号作为键
    private static final Map<String, Ticket> TICKET_MAP = new ConcurrentHashMap<>();
    private final ShowService showService;
    private final HallService hallService;
    private final MovieService movieService;
    private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd");

    public TicketServiceImpl(ShowService showService) {
        this.showService = showService;
        this.hallService = new HallServiceImpl();
        this.movieService = new MovieServiceImpl();
    }

    @Override
    public Ticket sellTicket(String showId, List<String> seatIds, boolean isChild) throws Exception {
        // 1. 校验场次是否存在
        Show show = showService.getShowById(showId);
        if (show == null) {
            throw new Exception("场次不存在");
        }

        // 2. 校验场次状态
        if (!"未开始".equals(show.getStatus())) {
            throw new Exception("该场次已开始或已结束，不能售票");
        }

        // 3. 校验座位是否可用
        List<String> soldSeats = getSoldSeats(showId);
        for (String seatId : seatIds) {
            if (soldSeats.contains(seatId)) {
                throw new Exception("座位" + seatId + "已售出");
            }
        }

        // 4. 计算票价（含折扣）
        double price = show.getPrice();
        if (isChild) {
            price *= 0.5; // 儿童票半价
        }

        // 早场折扣（10点前9折）
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(show.getShowTime());
        if (calendar.get(Calendar.HOUR_OF_DAY) < 10) {
            price *= 0.9;
        }

        double totalPrice = price * seatIds.size();
        totalPrice = Math.round(totalPrice * 100) / 100.0; // 保留两位小数

        // 5. 生成唯一票号
        String ticketId = IdGenerator.generateTicketId();

        // 6. 创建票对象并存储
        Ticket ticket = new Ticket(ticketId, showId, seatIds, new Date(), totalPrice, isChild, false);
        TICKET_MAP.put(ticketId, ticket);

        // 7. 记录售票日志
        LogUtil.log("售票操作：票号=" + ticketId + "，场次=" + showId + "，座位=" + seatIds + "，总价=" + totalPrice);

        return ticket;
    }

    public void interactiveSellTicket(String showId) throws Exception {
        // 1. 校验场次是否存在
        Show show = showService.getShowById(showId);
        if (show == null) {
            throw new Exception("场次不存在");
        }

        // 2. 校验场次状态
        if (!"未开始".equals(show.getStatus())) {
            throw new Exception("该场次已开始或已结束，不能售票");
        }

        // 3. 获取放映厅信息
        Hall hall = hallService.getHallById(show.getHallId());
        if (hall == null) {
            throw new Exception("放映厅信息不存在");
        }

        // 4. 显示座位布局并选择座位
        List<String> seatIds = selectSeats(hall, showId);
        if (seatIds.isEmpty()) {
            System.out.println("未选择座位，取消售票");
            return;
        }

        // 5. 判断是否为儿童票
        System.out.print("是否为儿童票(1-是,0-否): ");
        boolean isChild = InputUtil.inputInteger() == 1;

        // 6. 计算票价（含折扣）
        double price = show.getPrice();
        if (isChild) {
            price *= 0.5; // 儿童票半价
        }

        // 早场折扣（10点前9折）
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(show.getShowTime());
        if (calendar.get(Calendar.HOUR_OF_DAY) < 10) {
            price *= 0.9;
        }

        double totalPrice = price * seatIds.size();
        totalPrice = Math.round(totalPrice * 100) / 100.0; // 保留两位小数

        // 7. 生成唯一票号
        String ticketId = IdGenerator.generateTicketId();

        // 8. 创建票对象并存储
        Ticket ticket = new Ticket(ticketId, showId, seatIds, new Date(), totalPrice, isChild, false);
        TICKET_MAP.put(ticketId, ticket);

        // 9. 记录售票日志
        LogUtil.log("售票操作：票号=" + ticketId + "，场次=" + showId + "，座位=" + seatIds + "，总价=" + totalPrice);

        // 10. 显示票务信息
        displayTicketInfo(ticket, show, hall);
    }

    /**
     * 选择座位的方法
     */
    private List<String> selectSeats(Hall hall, String showId) throws Exception {
        List<String> soldSeats = getSoldSeats(showId);
        List<String> selectedSeats = new ArrayList<>();

        while (true) {
            // 显示座位布局
            displaySeatLayout(hall, soldSeats, selectedSeats);

            System.out.println("请选择操作:");
            System.out.println("1. 选择座位");
            System.out.println("2. 取消已选座位");
            System.out.println("3. 确认选座");
            System.out.println("4. 取消选座");

            int choice = InputUtil.inputInteger();

            switch (choice) {
                case 1:
                    System.out.print("请输入座位行号(1-" + hall.getRowCount() + "): ");
                    int row = InputUtil.inputInteger();
                    System.out.print("请输入座位列号(1-" + hall.getColCount() + "): ");
                    int col = InputUtil.inputInteger();

                    if (row < 1 || row > hall.getRowCount() || col < 1 || col > hall.getColCount()) {
                        System.out.println("座位号超出范围");
                        break;
                    }

                    String seatId = row + "," + col;
                    if (soldSeats.contains(seatId)) {
                        System.out.println("该座位已售出");
                        break;
                    }

                    if (selectedSeats.contains(seatId)) {
                        System.out.println("该座位已选择");
                        break;
                    }

                    selectedSeats.add(seatId);
                    System.out.println("座位" + seatId + "已选择");
                    break;

                case 2:
                    if (selectedSeats.isEmpty()) {
                        System.out.println("没有已选座位");
                        break;
                    }

                    System.out.println("已选座位: " + selectedSeats);
                    System.out.print("请输入要取消的座位(行号,列号): ");
                    String cancelSeat = InputUtil.inputString();

                    if (selectedSeats.remove(cancelSeat)) {
                        System.out.println("座位" + cancelSeat + "已取消");
                    } else {
                        System.out.println("未选择该座位");
                    }
                    break;

                case 3:
                    if (selectedSeats.isEmpty()) {
                        System.out.println("未选择任何座位");
                        break;
                    }
                    return selectedSeats;

                case 4:
                    return new ArrayList<>(); // 返回空列表表示取消选座

                default:
                    System.out.println("无效选择");
            }
        }
    }

    /**
     * 显示座位布局
     */
    private void displaySeatLayout(Hall hall, List<String> soldSeats, List<String> selectedSeats) {
        int rows = hall.getRowCount();
        int cols = hall.getColCount();

        System.out.print("  ");
        for (int j = 1; j <= cols; j++) {
            System.out.printf("%3d", j);
        }
        System.out.println();

        for (int i = 1; i <= rows; i++) {
            System.out.printf("%2d", i);
            for (int j = 1; j <= cols; j++) {
                String seatId = i + "," + j;
                if (soldSeats.contains(seatId)) {
                    System.out.print("  x");  // 已售座位
                } else if (selectedSeats.contains(seatId)) {
                    System.out.print("  *");  // 已选座位
                } else {
                    System.out.print("  o");  // 空闲座位
                }
            }
            System.out.println();
        }

        System.out.println("座位状态: o-空闲  x-已售  *-已选");
        System.out.println("总座位数: " + (rows * cols) + ", 已售: " + soldSeats.size() + ", 空闲: " + (rows * cols - soldSeats.size() - selectedSeats.size()) + ", 已选: " + selectedSeats.size());
    }

    /**
     * 显示票务信息
     */
    private void displayTicketInfo(Ticket ticket, Show show, Hall hall) throws Exception {
        Movie movie = movieService.getMovieById(show.getMovieId());
        if (movie == null) {
            throw new Exception("影片信息不存在");
        }

        System.out.println("\n=== 票务信息 ===");
        System.out.println("影片名称: " + movie.getName());
        System.out.println("放映时间: " + show.getShowTime());
        System.out.println("放映厅: " + hall.getName());
        System.out.println("座位号: " + ticket.getSeatIds());
        System.out.println("票价: " + ticket.getTotalPrice());
        System.out.println("票号: " + ticket.getTicketId());
        System.out.println("售票成功!");
    }

    @Override
    public boolean refundTicket(String ticketId) throws Exception {
        Ticket ticket = TICKET_MAP.get(ticketId);
        if (ticket == null) {
            throw new Exception("票不存在");
        }
        if (ticket.isRefunded()) {
            throw new Exception("该票已退票");
        }

        // 校验是否在放映前1小时
        Show show = showService.getShowById(ticket.getShowId());
        long timeDiff = show.getShowTime().getTime() - new Date().getTime();
        if (timeDiff < 3600 * 1000) { // 小于1小时
            throw new Exception("距离放映不足1小时，不允许退票");
        }

        // 计算退款金额（提前1天全退，否则扣10%）
        long dayDiff = timeDiff / (24 * 3600 * 1000);
        double refundAmount = ticket.getTotalPrice();
        if (dayDiff < 1) {
            refundAmount *= 0.9;
        }
        refundAmount = Math.round(refundAmount * 100) / 100.0; // 保留两位小数

        // 标记为已退票
        ticket.setRefunded(true);
        TICKET_MAP.put(ticketId, ticket);

        // 记录退票日志
        LogUtil.log("退票操作：票号=" + ticketId + "，退款金额=" + refundAmount);
        System.out.println("实际退款金额: " + refundAmount);
        return true;
    }

    @Override
    public List<String> getSoldSeats(String showId) {
        List<String> soldSeats = new ArrayList<>();
        for (Ticket ticket : TICKET_MAP.values()) {
            if (!ticket.isRefunded() && ticket.getShowId().equals(showId)) {
                soldSeats.addAll(ticket.getSeatIds());
            }
        }
        return soldSeats;
    }

    @Override
    public Ticket getTicketByTicketId(String ticketId) {
        return TICKET_MAP.get(ticketId);
    }

    @Override
    public void statisticsByDay() {
        System.out.println("\n=== 按日销售统计 ===");
        System.out.print("请输入日期(yyyy-MM-dd): ");
        String dateStr = InputUtil.inputString();

        try {
            Date targetDate = SDF.parse(dateStr);
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(targetDate);
            calendar.add(Calendar.DAY_OF_MONTH, 1);
            Date nextDay = calendar.getTime();

            System.out.println(dateStr + " 销售统计:");
            System.out.printf("%-15s %-10s %-10s %-10s %-10s %-10s\n", "场次ID", "销售票数", "单价", "退票数", "退票金额", "总票价");

            // 用于存储每场次的统计信息
            Map<String, ShowStatistics> showStats = new HashMap<>();

            // 遍历所有票，统计每场次的销售和退票信息
            for (Ticket ticket : TICKET_MAP.values()) {
                Show show = showService.getShowById(ticket.getShowId());
                if (show == null) continue;

                // 检查票的销售时间是否在目标日期内
                if (ticket.getSaleTime().after(targetDate) && ticket.getSaleTime().before(nextDay)) {
                    String showId = show.getShowId();
                    ShowStatistics stats = showStats.computeIfAbsent(showId, k -> new ShowStatistics(showId, show.getPrice()));

                    if (ticket.isRefunded()) {
                        // 退票统计
                        stats.refundCount++;
                        // 简化处理，实际退票金额计算可能更复杂
                        stats.refundAmount += ticket.getTotalPrice();
                    } else {
                        // 销售统计
                        stats.saleCount += ticket.getSeatIds().size();
                        stats.totalSales += ticket.getTotalPrice();
                    }
                }
            }

            // 显示每场次的统计信息
            for (ShowStatistics stats : showStats.values()) {
                System.out.printf("%-15s %-10d %-10.2f %-10d %-10.2f %-10.2f\n",
                        stats.showId, stats.saleCount, stats.unitPrice,
                        stats.refundCount, stats.refundAmount, stats.totalSales);
            }

            // 计算并显示总计
            int totalSaleCount = showStats.values().stream().mapToInt(s -> s.saleCount).sum();
            double totalRefundAmount = showStats.values().stream().mapToDouble(s -> s.refundAmount).sum();
            double grandTotalSales = showStats.values().stream().mapToDouble(s -> s.totalSales).sum();

            System.out.println("------------------------------------------------------------------------");
            System.out.printf("%-15s %-10d %-10s %-10s %-10.2f %-10.2f\n",
                    "总计", totalSaleCount, "", "", totalRefundAmount, grandTotalSales);

        } catch (Exception e) {
            System.out.println("统计失败: " + e.getMessage());
        }
    }

    // 用于存储每场次统计信息的内部类
    private static class ShowStatistics {
        String showId;
        double unitPrice;
        int saleCount = 0;
        int refundCount = 0;
        double refundAmount = 0.0;
        double totalSales = 0.0;

        ShowStatistics(String showId, double unitPrice) {
            this.showId = showId;
            this.unitPrice = unitPrice;
        }
    }

    @Override
    public void statisticsByWeek() {
        System.out.println("\n=== 按周销售统计 ===");
        System.out.print("请输入日期(yyyy-MM-dd)，将统计该日期所在周: ");
        String dateStr = InputUtil.inputString();

        try {
            Date targetDate = SDF.parse(dateStr);
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(targetDate);
            calendar.setFirstDayOfWeek(Calendar.MONDAY); // 设置周一为一周的第一天
            calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
            Date weekStart = calendar.getTime();

            calendar.add(Calendar.DAY_OF_MONTH, 7);
            Date weekEnd = calendar.getTime();

            System.out.println(SDF.format(weekStart) + " 到 " + SDF.format(weekEnd) + " 销售统计:");
            System.out.printf("%-15s %-10s %-10s %-10s %-10s %-10s\n", "场次ID", "销售票数", "单价", "退票数", "退票金额", "总票价");

            // 用于存储每场次的统计信息
            Map<String, ShowStatistics> showStats = new HashMap<>();

            // 遍历所有票，统计每场次的销售和退票信息
            for (Ticket ticket : TICKET_MAP.values()) {
                Show show = showService.getShowById(ticket.getShowId());
                if (show == null) continue;

                // 检查票的销售时间是否在目标周内
                if (ticket.getSaleTime().after(weekStart) && ticket.getSaleTime().before(weekEnd)) {
                    String showId = show.getShowId();
                    ShowStatistics stats = showStats.computeIfAbsent(showId, k -> new ShowStatistics(showId, show.getPrice()));

                    if (ticket.isRefunded()) {
                        // 退票统计
                        stats.refundCount++;
                        // 简化处理，实际退票金额计算可能更复杂
                        stats.refundAmount += ticket.getTotalPrice();
                    } else {
                        // 销售统计
                        stats.saleCount += ticket.getSeatIds().size();
                        stats.totalSales += ticket.getTotalPrice();
                    }
                }
            }

            // 显示每场次的统计信息
            for (ShowStatistics stats : showStats.values()) {
                System.out.printf("%-15s %-10d %-10.2f %-10d %-10.2f %-10.2f\n",
                        stats.showId, stats.saleCount, stats.unitPrice,
                        stats.refundCount, stats.refundAmount, stats.totalSales);
            }

            // 计算并显示总计
            int totalSaleCount = showStats.values().stream().mapToInt(s -> s.saleCount).sum();
            double totalRefundAmount = showStats.values().stream().mapToDouble(s -> s.refundAmount).sum();
            double grandTotalSales = showStats.values().stream().mapToDouble(s -> s.totalSales).sum();

            System.out.println("------------------------------------------------------------------------");
            System.out.printf("%-15s %-10d %-10s %-10s %-10.2f %-10.2f\n",
                    "总计", totalSaleCount, "", "", totalRefundAmount, grandTotalSales);

        } catch (Exception e) {
            System.out.println("统计失败: " + e.getMessage());
        }
    }

    @Override
    public void statisticsByMonth() {
        System.out.println("\n=== 按月销售统计 ===");
        System.out.print("请输入年月(yyyy-MM): ");
        String dateStr = InputUtil.inputString();

        try {
            Date targetDate = new SimpleDateFormat("yyyy-MM").parse(dateStr);
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(targetDate);
            calendar.set(Calendar.DAY_OF_MONTH, 1);
            Date monthStart = calendar.getTime();

            calendar.add(Calendar.MONTH, 1);
            Date monthEnd = calendar.getTime();

            System.out.println(dateStr + " 销售统计:");
            System.out.printf("%-15s %-10s %-10s %-10s %-10s %-10s\n", "场次ID", "销售票数", "单价", "退票数", "退票金额", "总票价");

            // 用于存储每场次的统计信息
            Map<String, ShowStatistics> showStats = new HashMap<>();

            // 遍历所有票，统计每场次的销售和退票信息
            for (Ticket ticket : TICKET_MAP.values()) {
                Show show = showService.getShowById(ticket.getShowId());
                if (show == null) continue;

                // 检查票的销售时间是否在目标月内
                if (ticket.getSaleTime().after(monthStart) && ticket.getSaleTime().before(monthEnd)) {
                    String showId = show.getShowId();
                    ShowStatistics stats = showStats.computeIfAbsent(showId, k -> new ShowStatistics(showId, show.getPrice()));

                    if (ticket.isRefunded()) {
                        // 退票统计
                        stats.refundCount++;
                        // 简化处理，实际退票金额计算可能更复杂
                        stats.refundAmount += ticket.getTotalPrice();
                    } else {
                        // 销售统计
                        stats.saleCount += ticket.getSeatIds().size();
                        stats.totalSales += ticket.getTotalPrice();
                    }
                }
            }

            // 显示每场次的统计信息
            for (ShowStatistics stats : showStats.values()) {
                System.out.printf("%-15s %-10d %-10.2f %-10d %-10.2f %-10.2f\n",
                        stats.showId, stats.saleCount, stats.unitPrice,
                        stats.refundCount, stats.refundAmount, stats.totalSales);
            }

            // 计算并显示总计
            int totalSaleCount = showStats.values().stream().mapToInt(s -> s.saleCount).sum();
            double totalRefundAmount = showStats.values().stream().mapToDouble(s -> s.refundAmount).sum();
            double grandTotalSales = showStats.values().stream().mapToDouble(s -> s.totalSales).sum();

            System.out.println("------------------------------------------------------------------------");
            System.out.printf("%-15s %-10d %-10s %-10s %-10.2f %-10.2f\n",
                    "总计", totalSaleCount, "", "", totalRefundAmount, grandTotalSales);

        } catch (Exception e) {
            System.out.println("统计失败: " + e.getMessage());
        }
    }

    // 用于存储每场次统计信息的内部类
    private static class ShowStatistics2 {
        String showId;
        double unitPrice;
        int saleCount = 0;
        int refundCount = 0;
        double refundAmount = 0.0;
        double totalSales = 0.0;

        ShowStatistics2(String showId, double unitPrice) {
            this.showId = showId;
            this.unitPrice = unitPrice;
        }
    }
}